using System;
using System.Collections;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using Framework.Interface;
using Framework.Manager;
using Framework.Singleton;
using Framework.UI;
using Shared.UI;
using UnityEngine;

public class UIManager : MonoSingleton<UIManager>, IMonoManager
{
    public Transform uiRoot;
    public Dictionary<string, Transform> layers = new Dictionary<string, Transform>();
    public Transform disable;
    
    private Canvas canvasTemplete;
    
    private Dictionary<Enum, UIController> caches = new Dictionary<Enum, UIController>();
    private Stack<UIController> stack = new Stack<UIController>();

    private Dictionary<Enum, string> lockupMap = new();
    
    public async UniTask Initialize(Transform parent)
    {
        transform.SetParent(parent);
        await UniTask.CompletedTask;

        await LoadUI();
        await InitUILayer();
    }

    public void Shutdown()
    {
        Dispose().ToCoroutine();
    }

    #region 切换场景时锁定UI资源
    public void AddLock(Enum uid)
    {
        if (!lockupMap.TryGetValue(uid, out string resPath))
        {
            if (caches.TryGetValue(uid, out UIController cache))
            {
                UDefModel uDef = UIDefine.defines[uid];
                resPath = $"{cache.ResDir}/{uDef.Module}View.prefab";
                
                ResourceManager.Instance.AddLockResource(resPath);
                
                lockupMap.Add(uid, resPath);
            }
        }
    }

    public void RemoveLock(Enum uid)
    {
        if (lockupMap.TryGetValue(uid, out string resPath))
        {
            ResourceManager.Instance.AddLockResource(resPath);
        }
        lockupMap.Remove(uid);
    }

    private bool CheckInLock(Enum uid)
    {
        return lockupMap.ContainsKey(uid);
    }
    #endregion
    
    // 释放没有锁定的UI资源
    public async UniTask Dispose()
    {
        stack.Clear();
        
        List<Enum> removeList = new List<Enum>();
        
        foreach (KeyValuePair<Enum, UIController> cache in caches)
        {
            if (CheckInLock(cache.Key))
            {
                continue;
            }
            
            // 取出没有被锁定的UI资源
            removeList.Add(cache.Key);
            
            await cache.Value.Destroy();
        }
        
        if (removeList.Count > 0)
        {
            for (int i = 0; i < removeList.Count; i++)
            {
                caches.Remove(removeList[i]);
            }
        }
        removeList = null;
    }

    public async UniTask<T> Active<T>(Enum uid, UIArg args = null) where T : UIController, new()
    {
        await UniTask.CompletedTask;
        
        T nextController = null;

        if (caches.ContainsKey(uid))
        {
            nextController = caches[uid] as T;
            
            // 当前正在显示中
            if (nextController.Actived)
                return nextController;
        }
        
        if (!UIDefine.defines.TryGetValue(uid, out UDefModel curDef))
        {
            Debug.LogError($"{uid.ToString()} has not been defined.");
            return null;
        }

        UIController curController = null;
        
        // 底层
        bool topUI = curDef.Type == UIType.Fixed && curDef.Node == UINode.Top;
        // Debug.Log($"=====  {uid.ToString()}  {curDef.Type.ToString()}  {curDef.Node.ToString()}  {curDef.Layer}");
        if (topUI)
        {
            if (stack.Count > 0)
            {
                // 界面已经加载过
                // 当前界面， 关闭，弹出栈
                curController = stack.Peek();
            }
        }
        
        // 要加载的界面已经加载过
        if (nextController != null)
        {
            // 底层界面
            if (topUI)
            {
                nextController.SetLayer(layers[curDef.Layer]);
                await nextController.OnReopen();
                
                // 入栈
                stack.Push(nextController);
                
                // 把上一个界面隐藏
                if (curController != null)
                {
                    await curController.OnPause();
                    curController.SetLayer(disable);
                }
            }
            else
            {
                Transform layer = null;
                
                // 此种情况是弹框之类的
                if (curDef.Node == UINode.Top)
                {
                    if (args == null)
                    {
                        if (args.parent = null)
                            layer = nextController.Transform;
                        else
                            layer = args.parent;
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(curDef.Layer))
                            layer = nextController.Transform;
                        else
                            layer = layers[curDef.Layer];
                    }
                }
                else // node
                {
                    // 挂载节点
                    UIController upController = caches[curDef.UpId];
                    if (upController == null)
                    {
                        // 一般很少出现这种情况
                        Debug.LogError($"up view of {uid.ToString()} has not been loaded.");
                        return null;
                    }
                    
                    upController.AddChild(nextController);

                    layer = upController.Transform.Find(curDef.Layer);
                }
                
                nextController.SetLayer(layer);
                await nextController.OnOpen();
            }
            
            // 有缓存
            return nextController;
        }
        
        // 尚未加载过

        UIController upperController = null;
        if (curDef.Node == UINode.Node)
        {
            if (!curDef.UpId.Equals(UIId.None) && !caches.TryGetValue(curDef.UpId, out upperController))
            {
                Debug.LogError($"up view {curDef.UpId.ToString()} of view {uid.ToString()} has not been loaded.");
                return nextController;
            }
        }
        
        // 实例化
        nextController = new T();
        nextController.SetArgs(uid, args);
        // 加入缓存
        caches.Add(uid, nextController);
        if (topUI)
            stack.Push(nextController);

        if (curDef.Node == UINode.Node && upperController != null)
            nextController.ResDir = upperController.ResDir + "/" + curDef.Module;
        else
            nextController.ResDir = UIDefine.uiDir + "/" + curDef.Module;

        string resPath = $"{nextController.ResDir}/{curDef.Module}View.prefab";
        GameObject prefab = await ResourceManager.Instance.LoadPrefabAsync(resPath);
        if (prefab == null)
        {
            Debug.LogError($"load prefab of {uid.ToString()} fail at path {resPath}.");
            return nextController;
        }

        GameObject obj = GameObject.Instantiate(prefab);
        obj.name = prefab.name;

        nextController.Target = obj;
        
        // 为view的controller赋值
        UIView uiView = obj.GetComponent<UIView>();
        if (uiView == null)
        {
            Debug.LogError($"view component must be add, but not this one.");
            return nextController;
        }
        uiView.controller = nextController;

        Transform nLayer;
        if (curDef.Node == UINode.Node)
        {
            upperController.AddChild(nextController);
            nLayer = upperController.Transform.Find(curDef.Layer);
        }
        else
        {
            nLayer = string.IsNullOrEmpty(curDef.Layer) ? nextController.Transform : layers[curDef.Layer];
            if (curDef.Type == UIType.Shared)
                nLayer = (args == null || args.parent == null) ? nLayer : args.parent;
            // Debug.Log("&&&&&&&  " + nextController.Target.name + "  " + nLayer.name);
        }
        
        nextController.SetLayer(nLayer);
        await nextController.OnOpen();
        
        // 把上一个界面隐藏
        if (curController != null)
        {
            await curController.OnPause();
            curController.SetLayer(disable);
        }

        return nextController;
    }

    public async UniTask Deactive(Enum uid = null)
    {
        if (!UIDefine.defines.TryGetValue(uid, out UDefModel curDef))
        {
            Debug.LogError($"deactive view {uid.ToString()} fail, because of not being deined.");
            return;
        }
        
        // 底层界面
        bool isTop = curDef.Type == UIType.Fixed && curDef.Node == UINode.Top;
        if (isTop)
        {
            // 栈里少于1，则不再处理
            if (stack.Count <= 1)
                return;
            
            // 界面已经加载过
            // 当前界面要关闭，弹出栈
            UIController curController = stack.Pop();

            UIController nextController = stack.Peek();
            await nextController.OnReopen();
            nextController.SetLayer(layers[curDef.Layer]);
            
            curController.SetLayer(disable);
            await curController.OnClose();
        }
        else
        {
            UIController curController = caches[uid];
            curController.SetLayer(disable);
            await curController.OnClose();

            if (curDef.Node == UINode.Node)
            {
                UIController upController = caches[curDef.UpId];
                if (upController == null)
                {
                    Debug.LogError($"up view of view {uid.ToString()} has not been loaded.");
                    return;
                }
                upController.RemoveChild(curController);
            }
        }
    }

    private async UniTask LoadUI()
    {
        GameObject rootPrefab = await ResourceManager.Instance.LoadPrefabAsync(UIDefine.uiPath);
        if (rootPrefab == null)
        {
            Debug.LogError($"load prefab fail at {UIDefine.uiPath}.");
            return;
        }

        GameObject rootObj = GameObject.Instantiate(rootPrefab);
        rootObj.name = rootPrefab.name;
        uiRoot = rootObj.transform;

        canvasTemplete = uiRoot.Find("Canvas").GetComponent<Canvas>();
        
        DontDestroyOnLoad(rootObj);
    }

    private async UniTask InitUILayer()
    {
        await UniTask.CompletedTask;

        for (int i = 0; i < UIDefine.layers.Count; i++)
        {
            UILayer uiLayer = UIDefine.layers[i];
            
            Canvas canvas = GameObject.Instantiate(canvasTemplete, uiRoot, false);
            canvas.name = uiLayer.Name;
            canvas.sortingOrder = uiLayer.SortLayer;
            
            layers.Add(uiLayer.Name, canvas.transform);
        }

        disable = canvasTemplete.transform;
        disable.gameObject.SetActive(false);
    }
}
